package net.guerlab.loadbalancer;

import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;

/**
 * weight random Load Balancer
 *
 * @param <T>
 *         target class
 * @param <C>
 *         choose reference object
 * @author guer
 */
public class WeightRandomLoadBalancer<T, C> extends AbstractLoadBalancer<T, C> {

    private final Map<T, Integer> weightMap = new ConcurrentHashMap<>();

    /**
     * instantiation Load Balancer with CopyOnWriteArrayList
     */
    public WeightRandomLoadBalancer() {
        super();
    }

    /**
     * instantiation Load Balancer with appoint list
     *
     * @param targetList
     *         target object list
     */
    public WeightRandomLoadBalancer(List<TargetWrapper<T>> targetList) {
        super(targetList);
    }

    @Override
    protected void afterAdd(TargetWrapper<T> wrapper) {
        weightMap.put(wrapper.getTarget(), MIN_WEIGHT);
    }

    @Override
    protected void afterRemove(TargetWrapper<T> wrapper) {
        weightMap.remove(wrapper.getTarget());
    }

    @Override
    public void setWeight(T target, int weight) {
        if (target == null) {
            return;
        }

        weightMap.put(target, Math.max(weight, MIN_WEIGHT));
    }

    @Override
    protected T choose0(List<TargetWrapper<T>> activeTargetList, C chooseReferenceObject) {
        WeightList<T> targetList = new WeightList<>(activeTargetList, weightMap);
        TargetWrapper<T> wrapper = targetList.get(new Random().nextInt(targetList.size()));
        return wrapper == null ? null : wrapper.getTarget();
    }
}
